﻿using System;
using System.Collections.Generic;
using System.Web;
using EOS.Framework.Contracts.Web.Routing;
using EOS.Framework.Kernel;
using System.Globalization;

namespace EOS.Framework.Web.Mvc
{
    public class Dispatcher : IDispatcher
    {
        class PageContextImplementation : PageContext
        {        
            /// <summary>
            /// Initializes a new instance of the <see cref="PageContextImplementation"/> class.
            /// </summary>
            public PageContextImplementation(HttpContext httpContext, string url, string applicationPath, 
                string page, string action, ParameterDictionary parameters)
                : base(httpContext, url, applicationPath, page, action, parameters)
            { }
        }

        /// <summary>
        /// Dispatches the specified context.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="currentRoute">The current route.</param>
        public void Dispatch(HttpContext context, MatchingRoute currentRoute)
        {
            IContainerFactory factory = Unity.Current.Resolve<IContainerFactory>();

            factory.StartRequest();

            MvcConfigurationSection config = MvcConfiguration.Current;

            IWebPage page = factory.CreateWebPage((string)currentRoute.Parameters["webPage"]);
            if (page == null)
            {
                if (context.Request.Url.AbsoluteUri.EndsWith(config.ErrorSite))
                {
                    context.Response.StatusCode = 404;
                    context.Response.StatusDescription = "Page not found!";

                    return;
                }
                else
                {
                    switch (config.PageNotFoundBehaviour)
                    {
                        case PageNotFoundBehaviour.Response404:
                            {
                                context.Response.StatusCode = 404;
                                context.Response.StatusDescription = "Page not found!";

                                return;
                            }
                        case PageNotFoundBehaviour.Redirect:
                            {
                                context.Response.Redirect(config.ErrorSite);
                                break;
                            }
                        case PageNotFoundBehaviour.ThrowException:
                            {
                                throw new WebPageNotFoundException(string.Format(CultureInfo.CurrentCulture, Properties.Resources.PageNotFound,
                                   (string)currentRoute.Parameters["webPage"]));
                            }
                    }
                }
            }

            ParameterDictionary parameters = new ParameterDictionary();
            foreach (KeyValuePair<string, object> routingParameters in currentRoute.Parameters)
            {
                if (routingParameters.Key != "webPage" ||
                    routingParameters.Key != "action")
                {
                    parameters.Add(routingParameters.Key, routingParameters.Value);
                }
            }

            PageContext pageContext = new PageContextImplementation(context,
                context.Request.Url.AbsoluteUri,
                context.Request.ApplicationPath,
                (string)currentRoute.Parameters["webPage"],
                (string)currentRoute.Parameters["action"],
                parameters);

            List<IFilter> filters = new List<IFilter>(Unity.Current.ResolveAll<IFilter>());
            foreach (IFilter filter in filters)
            {
                filter.Execute(pageContext);
            }

            page.Execute(pageContext);
        }
    }
}
